package webdav

import (
	"fmt"
	"golang.org/x/net/webdav"
	"io/fs"
	"log"
	"my189go/pkg"
	"net/http"
	"os"
	"path/filepath"
	"sync"
)

func newRead(app pkg.Drive, name string) (webdav.File, error) {
	stat, err := app.Stat(name)
	if err != nil {
		return nil, err
	}
	return &read{app: app, name: name, stat: stat.(pkg.File)}, nil
}

var empty = &read{}

type read struct {
	app       pkg.Drive
	name      string
	stat      pkg.File
	load      sync.Once
	temp      *os.File
	readCount int
	resp      *http.Response
}

func (r *read) getTemp() *os.File {
	r.load.Do(func() {
		dir, name := filepath.Split(r.name)
		tempDir := os.TempDir() + "/cloud189" + dir
		_, err := os.Stat(tempDir)
		if os.IsNotExist(err) {
			err := os.MkdirAll(tempDir, 0755)
			if err != nil {
				log.Println(err)
				return
			}
		}
		r.app.Download(tempDir, r.name)
		if name+".osz" == r.stat.Name() {
			name = name + ".osz"
		}
		r.temp, _ = os.OpenFile(tempDir+"/"+name, os.O_CREATE|os.O_RDWR, 0644)
	})
	return r.temp
}
func (r *read) getWebTemp() *http.Response {
	if r.resp == nil {
		log.Println(r.name + " getWebTemp")
		var ee error
		r.resp, ee = r.app.DownloadStream(r.name, int64(r.readCount))
		if ee != nil {
			log.Println(ee)
		}
	}
	return r.resp
}
func (r *read) Seek(offset int64, whence int) (int64, error) {
	// Seek规则：
	// 1. 如果是磁盘文件，则调用getTemp().Seek()
	// 2. 如果是网络文件，则调用getWebTemp().Body.Seek()
	// 3. 如果是网络文件，则 readCount 记录已读取的字节数，每次Read()调用后，readCount 增加读取的字节数
	// 4. 如果已读取的字节数等于文件大小，则关闭网络连接，seekCount归零
	// 5. Seek 0  2  返回文件大小
	// 6. Seek 0  0  重置readCount为 0 返回0， 重置网络连接
	// 7. Seek 正数 0  增加readCount ， 返回正数 ， 重置网络连接
	// 8. Seek 负数 0  减少readCount ， 返回负数 ， 重置网络连接
	//log.Println(r.name+" Seek", offset, whence)
	if r.app.GetDiskCase() {
		return r.getTemp().Seek(offset, whence)
	} else {
		size := r.stat.Size()
		if whence == 2 {
			return size, nil
		} else if whence == 0 {
			r.readCount = int(offset)
			r.resp = nil // 重置连接
			return offset, nil
		}
		return 0, nil
	}

}
func (r *read) Read(p []byte) (n int, err error) {
	if r.app.GetDiskCase() {
		return r.getTemp().Read(p)
	} else {
		readCount, err := r.getWebTemp().Body.Read(p)
		r.readCount += readCount
		if int64(r.readCount) >= r.stat.Size() {
			r.resp.Body.Close()
			r.resp = nil
			r.readCount = 0
			fmt.Println(r.name + " Read end")
		}
		return readCount, err
	}
	//log.Println(r.name+" Read", len(p))
}
func (r *read) Write(p []byte) (n int, err error) { return r.getTemp().Write(p) }
func (r *read) Close() error                      { return nil }
func (r *read) Readdir(count int) ([]fs.FileInfo, error) {
	data, err := r.app.ReadDir(r.name)
	if err != nil {
		return nil, err
	}
	files := make([]fs.FileInfo, len(data))
	for i, v := range data {
		files[i], _ = v.Info()
	}
	return files, err
}
func (r *read) Stat() (info fs.FileInfo, err error) {
	return r.stat, err
}
